﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

namespace TrainingCenterSystem.VocabularyManagement
{
    /// <summary>
    /// Helper class for writing collection data to an xml file.
    /// </summary>
    public class CollectionFileWriter
    {
        #region private members
        private XmlWriterSettings _settings;
        private XmlWriter _xmlWriter;
        private VocabularyCollection _collection;
        #endregion

        #region constructor(s)
        /// <summary>
        /// Creates an instance of the file writer
        /// </summary>
        /// <param name="coll">the existing collection</param>
        /// <param name="filename">the filename</param>
        public CollectionFileWriter(VocabularyCollection coll, string filename)
        {
            _collection = coll;
            this.init(filename);
            this.writeCollectionFile();
        }
        #endregion

        #region methods

        /// <summary>
        /// initialises the file writer, i.e. sets default values before writing the data.
        /// </summary>
        /// <param name="filename">the filename</param>
        private void init(string filename)
        {
            _settings = new XmlWriterSettings();
            _settings.NewLineChars = Environment.NewLine;
            _settings.NewLineOnAttributes = true;
            _settings.NewLineHandling = NewLineHandling.Replace;
            _settings.NewLineOnAttributes = false;
            _settings.CloseOutput = true;
            _settings.Indent = true;
            _xmlWriter = XmlWriter.Create(filename, _settings);
        }

        /// <summary>
        /// the main method for writing the file.
        /// </summary>
        private void writeCollectionFile()
        {
            _xmlWriter.WriteStartDocument();

            // Write comments
            _xmlWriter.WriteComment("File for storing VocabularyCollection");            

            // 1. Collection   
            _xmlWriter.WriteStartElement("VocabularyCollection");

            this.writeCollectionData();
            this.writeContextData();
            this.writeVocabulary();
            // write the end of document
            _xmlWriter.WriteEndDocument();

            // close writer
            _xmlWriter.Close();
        }

        /// <summary>
        /// writes the collection data
        /// </summary>
        private void writeCollectionData()
        {
            // 2. Collection data, such as name, user etc.
            /*_xmlWriter.WriteStartElement("ID", "");
            _xmlWriter.WriteString(_collection.FileName);
            _xmlWriter.WriteEndElement();*/

            _xmlWriter.WriteStartElement("CollectionName", "");
            _xmlWriter.WriteString(_collection.CollectionName);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Description", "");
            string description = _collection.CollectionDescription;
            if (description == null)
                description = "";
            _xmlWriter.WriteString(description);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Username", "");
            _xmlWriter.WriteString(_collection.CollectionUser.Username);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("AccessType", "");
            _xmlWriter.WriteString(_collection.CollectionAccess.ToString());
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("FileName", "");
            _xmlWriter.WriteString(_collection.FileName);
            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// writes the context data
        /// </summary>
        private void writeContextData()
        {
            // 3. context data
            _xmlWriter.WriteStartElement("Contexts", "");
            for (int i = 0; i < _collection.Contexts.Count; i++)
            {
                _xmlWriter.WriteStartElement("Context", "");
                _xmlWriter.WriteAttributeString("id", ((VocabularyContext)_collection.Contexts[i]).ContextID);
                _xmlWriter.WriteString(((VocabularyContext)_collection.Contexts[i]).ContextName);
                _xmlWriter.WriteEndElement();
            }
            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// A general method utsed for writing the vocabularies.
        /// </summary>
        private void writeVocabulary()
        {
            // 4. vocabularies
            _xmlWriter.WriteStartElement("Vocabularies", "");
            for (int i = 0; i < _collection.Words.Count; i++)
            {
                if (_collection.Words[i] is Noun)
                {
                    this.writeNoun((Noun)_collection.Words[i]);
                }
                else if (_collection.Words[i] is Verb)
                {
                    this.writeVerb((Verb)_collection.Words[i]);
                }
                else if (_collection.Words[i] is Adjective)
                {
                    this.writeAdjective((Adjective)_collection.Words[i]);
                }
                else if (_collection.Words[i] is GenericWord)
                {
                    this.writeGeneric((GenericWord)_collection.Words[i]);
                }
            }
            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// Writes attributes common for all word types, such as BaseValue, translations etc.
        /// </summary>
        /// <param name="baseValue">the base value</param>
        /// <param name="translations">the translations</param>
        /// <param name="collName">the name of the owning collection</param>
        /// <param name="contName">the name of the owning context</param>
        private void writeCommonValues(string baseValue, string translations, string collName, string contName)
        {
            _xmlWriter.WriteStartElement("BaseValue");
            _xmlWriter.WriteString(baseValue);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Translations");
            _xmlWriter.WriteString(translations);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("CollectionName");
            _xmlWriter.WriteString(collName);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("ContextName");
            _xmlWriter.WriteString(contName);
            _xmlWriter.WriteEndElement();


        }

        /// <summary>
        /// Writes a noun
        /// </summary>
        /// <param name="noun">the noun</param>
        private void writeNoun(Noun noun)
        {
            _xmlWriter.WriteStartElement("Noun");

            this.writeCommonValues(noun.BaseValue, noun.Translations, noun.CollectionName, noun.ContextName);

            _xmlWriter.WriteStartElement("Article");
            _xmlWriter.WriteString(noun.Article);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("DefinedSing");
            _xmlWriter.WriteString(noun.DefinedSingular);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("DefinedPl");
            _xmlWriter.WriteString(noun.DefinedPlural);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("UndefinedSing");
            _xmlWriter.WriteString(noun.UndefinedSingular);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("UndefinedPl");
            _xmlWriter.WriteString(noun.UndefinedPlural);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// writes a verb
        /// </summary>
        /// <param name="verb">the verb</param>
        private void writeVerb(Verb verb)
        {
            _xmlWriter.WriteStartElement("Verb");

            this.writeCommonValues(verb.BaseValue, verb.Translations, verb.CollectionName, verb.ContextName);

            _xmlWriter.WriteStartElement("Present");
            _xmlWriter.WriteString(verb.PresentForm);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Imperfect");
            _xmlWriter.WriteString(verb.ImperfectForm);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Supinum");
            _xmlWriter.WriteString(verb.Supinum);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("ParticipPerfect");
            _xmlWriter.WriteString(verb.ParticipPerfect);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("IsRegular");
            _xmlWriter.WriteString(verb.IsRegular.ToString());
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();            
        }
        
        /// <summary>
        /// writes an adjective
        /// </summary>
        /// <param name="adj">the adjective</param>
        private void writeAdjective(Adjective adj)
        {
            _xmlWriter.WriteStartElement("Adjective");

            this.writeCommonValues(adj.BaseValue, adj.Translations, adj.CollectionName, adj.ContextName);

            _xmlWriter.WriteStartElement("Comparative");
            _xmlWriter.WriteString(adj.Comparative);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteStartElement("Superlative");
            _xmlWriter.WriteString(adj.Superlative);
            _xmlWriter.WriteEndElement();

            _xmlWriter.WriteEndElement();
        }

        /// <summary>
        /// writes a generic word
        /// </summary>
        /// <param name="gen">the generic word</param>
        private void writeGeneric(GenericWord gen)
        {
            _xmlWriter.WriteStartElement("GenericWord");
            this.writeCommonValues(gen.BaseValue, gen.Translations, gen.CollectionName, gen.ContextName);
            _xmlWriter.WriteEndElement();
        }
        #endregion
    }
}
